﻿using System;
using System.Net;
#if SILVERLIGHT
using AbstraX.ClientInterfaces;
#else
using AbstraX.ServerInterfaces;
#endif
using System.Reflection;
using System.Runtime.Serialization;
using System.ComponentModel.DataAnnotations;
using AbstraX.XPathBuilder;
using System.Linq;
using System.Diagnostics;
using System.ServiceModel.DomainServices.Server;
using AbstraX.TypeMappings;
using System.Collections.Generic;
using System.Linq.Expressions;
using AssemblyProvider.Web.Entities;
using ControlProviders.ProviderInterfaces;
using ControlProviders.Contracts;
using AbstraX;
using AbstraX.Templates;
using AbstraX.AssemblyInterfaces;
using AbstraX.Bindings;
using AbstraX.Bindings.Interfaces;
using AbstraX.Contracts;
using MvvmTreeView;

namespace SLControlProvider.Web.Entities
{
    [DataContract, DebuggerDisplay("{ DebugInfo }"), ClientCodeGeneration(typeof(ControlClientInterfaceGenerator)), KnownType(typeof(AssemblyType)), KnownType(typeof(BaseType))]
    public class SLControl : IControl
    {
        private IAssemblyType type;
        private IBase parent;

        public SLControl()
        {
        }
       public IAbstraXExtension LoadExtention(IBase baseObject, ITreeNode treeNode)
        {
            return null;
        }

        public SLControl(IAssemblyType type, IBase parent)
        {
            this.type = type;
            this.parent = parent;
        }

        [DataMember]
        public float ChildOrdinal
        {
            get
            {
                return type.ChildOrdinal;
            }
        }

        [DataMember]
        public string DebugInfo
        {
            get
            {
                return type.DebugInfo;
            }
        }

        [Include, Association("Parent_BaseType", "ID", "ParentID"), ClientCodeGeneration(typeof(AbstraXClientInterfaceGenerator))]
        public BaseType DataType
        {
            get
            {
                return type.DataType;
            }
        }

        [DataMember, Key]
        public string ID
        {
            get
            {
                return type.ID;
            }
        }

        [DataMember]
        public bool IsContainer
        {
            get 
            {
                return type.IsContainer;
            }
        }

        [Association("Control_SLFieldAttributes", "ID", "ParentID")]
        public List<SLFieldAttribute> ControlFieldAttributes
        {
            get
            {
                var attributes = new List<SLFieldAttribute>();

                foreach (var attribute in type.FieldAttributes)
                {
                    attributes.Add(new SLFieldAttribute(attribute, this));
                }

                return attributes;
            }
        }

        [Association("Control_SLPropertyAttributes", "ID", "ParentID")]
        public List<SLPropertyAttribute> ControlPropertyAttributes
        {
            get
            {
                var attributes = new List<SLPropertyAttribute>();

                foreach (var attribute in type.PropertyAttributes)
                {
                    attributes.Add(new SLPropertyAttribute(attribute, this));
                }

                return attributes;
            }
        }

        public IEnumerable<IAttribute> Attributes
        {
            get 
            {
                var attributes = Queryable.Union(this.ControlPropertyAttributes.AsQueryable().Cast<IAttribute>().Select(a => a),
                    this.ControlFieldAttributes.AsQueryable().Cast<IAttribute>().Select(a => a));

                return attributes;
            }
        }

        [Association("Control_PropertyElements", "ID", "ParentID")]
        public List<SLPropertyElement> ControlPropertyElements
        {
            get
            {
                var elements = new List<SLPropertyElement>();

                foreach (var element in type.PropertyElements)
                {
                    elements.Add(new SLPropertyElement(element, this));
                }

                return elements;
            }
        }

        [Include, Association("Control_BaseTypes", "ID", "ParentID")]
        public List<AssemblyType> BaseTypes
        {
            get
            {
                var types = new List<AssemblyType>();
                var parentType = type.SystemType;

                while (parentType != null)
                {
                    types.Add(new AssemblyType(parentType, this));
                    parentType.GetInterfaces().ToList().ForEach(t => types.Add(new AssemblyType(t, this)));

                    parentType = parentType.BaseType;
                }

                return types;
            }
        }

        public IEnumerable<IElement> ChildElements
        {
            get 
            {
                var elements = Queryable.Union(this.ControlPropertyElements.AsQueryable().Cast<IElement>(), 
                    this.BaseTypes.AsQueryable().Cast<IElement>());

                return elements;
            }
        }

        [Association("Control_MethodsConstructors", "ID", "ParentID")]
        public List<SLOperation> ControlMethodsConstructors
        {
            get
            {
                List<SLOperation> controlMethodsConstructors = new List<SLOperation>();

                foreach (var method in type.MethodsConstructors.Where(o => o is MethodOperation).Cast<MethodOperation>())
                {
                    controlMethodsConstructors.Add(new SLMethodOperation(method, this));
                }

                foreach (var constructor in type.MethodsConstructors.Where(o => o is ConstructorOperation).Cast<ConstructorOperation>())
                {
                    controlMethodsConstructors.Add(new SLConstructorOperation(constructor, this));
                }

                return controlMethodsConstructors;
            }
        }

        public IEnumerable<IOperation> Operations
        {
            get
            {
                var operations = this.ControlMethodsConstructors.AsQueryable().Cast<IOperation>().Select(o => o);

                return operations;
            }
        }

        [DataMember]
        public string ParentID
        {
            get 
            {
                return type.ParentID;
            }
        }

        [DataMember]
        public string Name
        {
            get 
            {
                return type.Name;
            }
        }

        [DataMember]
        public string Description
        {
            get
            {
                return type.Description;
            }
        }

        [DataMember]
        public string Documentation
        {
            get
            {
                return type.Documentation;
            }
        }

        [DataMember]
        public string ImageURL
        {
            get
            {
                return type.ImageURL;
            }
        }

        [DataMember]
        public IBase Parent
        {
            get 
            {
                return type.Parent;
            }
        }

        [DataMember]
        public string FolderKeyPair 
        {
            get
            {
                return type.FolderKeyPair;
            }

            set
            {
                type.FolderKeyPair = value;
            }
        }

        public void ExecuteWhere(string property, object value)
        {
            type.ExecuteWhere(property, value);
        }

        public void ExecuteWhere(System.Linq.Expressions.Expression expression)
        {
            type.ExecuteWhere(expression);
        }

        public void ExecuteWhere(XPathAxisElement element)
        {
            type.ExecuteWhere(element);
        }

        public void ClearPredicates()
        {
            type.ClearPredicates();
        }

        public IRoot Root
        {
            get
            {
                IBase baseObject = this;

                while (baseObject != null)
                {
                    baseObject = baseObject.Parent;

                    if (baseObject is IRoot)
                    {
                        return (IRoot)baseObject;
                    }
                }

                return null;
            }
        }

        [DataMember]
        public DefinitionKind Kind
        {
            get
            {
                return type.Kind;
            }
        }

        [DataMember]
        public bool HasChildren
        {
            get 
            {
                return type.HasChildren;
            }
        }

        [DataMember, Include, Association("Parent_Facet", "ID", "ParentID")]
        public Facet[] Facets
        {
            get 
            {
                return type.Facets;
            }
        }

        public void Build(IBuildContext buildContext)
        {
        }

        public IEnumerable<IBindingsTreeNode> RootBindings
        {
            get 
            { 
                throw new NotImplementedException(); 
            }
        }

        [DataMember]
        public string BindingsTreeName
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        [Ignore]
        public IAbstraXProviderService AbstraXProviderService
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        [Exclude]
        public ContainerType AllowableContainerTypes
        {
            get { throw new NotImplementedException(); }
        }

        [Exclude]
        public ConstructType AllowableConstructTypes
        {
            get { throw new NotImplementedException(); }
        }


        public AbstraX.TypeMappings.ContainerType DefaultContainerType
        {
            get { throw new NotImplementedException(); }
        }

        public AbstraX.TypeMappings.ConstructType DefaultConstructType
        {
            get { throw new NotImplementedException(); }
        }
    }
}
